package mynl

import (
	"fmt"
	"strings"
)

/////////////////////////////////////////////////////////////////////////
// 语法分析
// 包括了AST的数据结构和递归下降的语法解析程序

//基类，标识AST的一个节点
type IAstNode interface {
	//打印对象信息，prefix是前面填充的字符串，通常用于缩进显示
	Dump(prefix string)
}

/**
 * 语句节点
 * 其子类包括函数声明和函数调用
 */
type IStatement interface {
	IAstNode
}

func isIStatementNode(node IAstNode) bool {
	if node == nil {
		return false
	}

	_, ok := interface{}(node).(IStatement)
	if ok {
		return true
	} else {
		return false
	}
}

/**
 * 程序节点，也是AST的根节点
 */
type Prog struct {
	IAstNode
	Stmts []IStatement //程序中可以包含多个语句
}

func newProg(Stmts []IStatement) *Prog {
	return &Prog{
		Stmts: Stmts,
	}
}

func (selfx *Prog) Dump(prefix string) {
	fmt.Println(prefix + "Prog")
	for _, stmt := range selfx.Stmts {
		stmt.Dump(prefix + "\t")
	}
}

/**
 * 函数声明节点
 */
type FunctionDecl struct {
	IStatement
	Name string       //函数名称
	Body FunctionBody //函数体
}

func newFunctionDecl(name string, body *FunctionBody) *FunctionDecl {
	return &FunctionDecl{
		Name: name,
		Body: *body,
	}

}

func (selfx *FunctionDecl) Dump(prefix string) {
	fmt.Println(prefix + "FunctionDecl " + selfx.Name)
	selfx.Body.Dump(prefix + "\t")
}

/**
 * 函数体节点
 */
type FunctionBody struct {
	IAstNode
	Stmts []FunctionCall
}

func newFunctionBody(Stmts []FunctionCall) *FunctionBody {
	return &FunctionBody{
		Stmts: Stmts,
	}
}

func isFunctionBodyNode(node *FunctionBody) bool {
	return node != nil
}

func (selfx *FunctionBody) Dump(prefix string) {
	fmt.Println(prefix + "FunctionBody")
	for _, stmt := range selfx.Stmts {
		stmt.Dump(prefix + "\t")
	}
}

/**
 * 函数调用节点
 */
type FunctionCall struct {
	IStatement
	Name       string
	Parameters []string
	Definition *FunctionDecl //指向函数的声明
}

func newFunctionCall(name string, parameters []string) *FunctionCall {
	return &FunctionCall{
		Name:       name,
		Parameters: parameters,
	}
}

func isFunctionCallNode(node *FunctionCall) bool {
	return node != nil
}

func (selfx *FunctionCall) Dump(prefix string) {
	if strings.HasPrefix(selfx.Name, "nl.") {
		fmt.Println(prefix + "SysFuncCall " + selfx.Name + ", resolved")
	} else if selfx.Definition != nil {
		fmt.Println(prefix + "FunctionCall " + selfx.Name + ", resolved")
	} else {
		fmt.Println(prefix + "FunctionCall " + selfx.Name + ", not resolved")
	}

	for _, p := range selfx.Parameters {
		fmt.Println(prefix + "\t" + "Parameter: " + p)
	}
}

/**
 * 对AST做遍历的Vistor。
 * 这是一个基类，定义了缺省的遍历方式。子类可以覆盖某些方法，修改遍历方式。
 */
type AstVisitor struct {
}

func (selfx *AstVisitor) VisitProg(prog *Prog) *IAstNode {
	var retVal *IAstNode
	for i := range prog.Stmts {
		//根据stmt的类型，进行不同的处理
		switch v := prog.Stmts[i].(type) {
		case *FunctionDecl:
			retVal = selfx.visitFunctionDecl(v)
		case *FunctionCall:
			retVal = selfx.visitFunctionCall(v)
		default:
		}
	}
	return retVal
}

//通过函数声明，访问函数体
//这里要看子类如何继承
func (selfx *AstVisitor) visitFunctionDecl(functionDecl *FunctionDecl) *IAstNode {
	return selfx.visitFunctionBody(&functionDecl.Body)
}

//函数体中，依次执行每个函数调用
func (selfx *AstVisitor) visitFunctionBody(functionBody *FunctionBody) *IAstNode {
	var retVal *IAstNode

	//依次执行函数体中的每个函数调用
	for i := range functionBody.Stmts {
		retVal = selfx.visitFunctionCall(&functionBody.Stmts[i])
	}
	return retVal
}

//执行1次函数调用
//这里要看子类如何继承
func (selfx *AstVisitor) visitFunctionCall(functionCall *FunctionCall) *IAstNode {
	return nil
}
